﻿using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Analysis
{
    class AssetItem
    {
        public string m_guid;
        public string m_path;
        /// <summary>
        /// 依赖的资源
        /// </summary>
        public List<string> m_depends = new List<string>();
        /// <summary>
        /// 被哪些资源引用
        /// </summary>
        public List<string> m_references = new List<string>();
    }

    interface IAssetFileSystem
    {

    }
    public class AssetFolder : IAssetFileSystem
    {
        public static Texture s_cachedIcon;
        public static Texture Icon
        {
            get
            {
                if (s_cachedIcon == null)
                {
                    s_cachedIcon = AssetDatabase.GetCachedIcon("Assets");
                }

                return s_cachedIcon;
            }
        }


        public string m_name = "点击 Refresh Data";
        public string m_path;
        public string m_guid;
        /// <summary>
        /// 默认折叠状态
        /// </summary>
        public bool m_foldout = false;

        public int m_depth = 0;

        public List<AssetFolder> m_folders = new List<AssetFolder>();
        public List<AssetFile> m_files = new List<AssetFile>();

        public Dictionary<string, AssetFolder> m_dictFolder = new Dictionary<string, AssetFolder>();

        public string Name
        {
            get => m_name;
            set => m_name = value;
        }
        public string Path
        {
            get => m_path;
            set => m_path = value;
        }
        public bool Foldout
        {
            get => m_foldout;
            set => m_foldout = value;
        }
        public int Count
        {
            get
            {
                return m_folders.Count + m_files.Count;
            }
        }
        public int Depth { get; set; }
        public bool Toggle { get; set; }

        public AssetFolder AddFolder(string name, string path, int depth)
        {
            AssetFolder folder = null;
            if (!m_dictFolder.TryGetValue(name, out folder))
            {
                folder = new AssetFolder()
                {
                    Name = name,
                    Path = path,
                    Depth = depth,
                };
                m_dictFolder.Add(name, folder);

                m_folders.Add(folder);
            }

            return folder;
        }

        public AssetFile AddFile(string name, string path, int depth)
        {
            AssetFile file = new AssetFile()
            {
                Name = name,
                Path = path,
                Depth = depth,
            };
            m_files.Add(file);

            return file;
        }
    }
    public class AssetFile : IAssetFileSystem
    {
        public string m_name;
        public string m_path;
        public string m_guid;
        public Texture m_cacheIcon;


        public string Name
        {
            get => m_name;
            set => m_name = value;
        }
        public string Path
        {
            get => m_path;
            set => m_path = value;
        }
        public int Depth { get; set; }

        public int DependCount { get; set; }
        public int ReferenceCount { get; set; }
        public Texture Icon
        {
            get
            {
                if (m_cacheIcon == null)
                {
                    m_cacheIcon = AssetDatabase.GetCachedIcon(m_path);
                }
                return m_cacheIcon;
            }
        }

        public bool Toggle { get; set; }
    }


    public class AssetReferenceWindow : EditorWindow
    {

        private Dictionary<string, AssetItem> m_dict = new Dictionary<string, AssetItem>();
        private List<AssetItem> m_list = new List<AssetItem>();

        private Dictionary<string, List<string>> m_dictDepend = new Dictionary<string, List<string>>();
        private Dictionary<string, List<string>> m_dictReference = new Dictionary<string, List<string>>();

        private List<string> m_listFiles = new List<string>();
        public Dictionary<string, AssetFile> m_dictPath2AssetFile = new Dictionary<string, AssetFile>();

        [MenuItem("Tools/资源合规/待归档/资源清理工具", false, 349)]
        static void OpenWindow()
        {
            AssetReferenceWindow window = GetWindow<AssetReferenceWindow>();
            window.position = new Rect(100, 100, 1334, 750);
            window.wantsMouseMove = false;
            window.titleContent = new GUIContent("资源清理工具");
            window.Show();
            window.Focus();
        }
        void OnGUI()
        {
            DrawOptionBar();
            DrawLayout();
        }
        //绘制上条
        void DrawOptionBar()
        {
            EditorGUILayout.BeginHorizontal();
            //刷新数据
            if (GUILayout.Button("Refresh Data"))
            {
                CollectData();

                //EditorGUIUtility.ExitGUI();
            }

            GUILayout.FlexibleSpace();

            //扩展
            if (GUILayout.Button("Expand"))
            {
                //if (m_AssetTreeView != null) m_AssetTreeView.ExpandAll();
            }
            //折叠
            if (GUILayout.Button("Collapse"))
            {
                //if (m_AssetTreeView != null) m_AssetTreeView.CollapseAll();
            }
            EditorGUILayout.EndHorizontal();
        }

        void DrawLayout()
        {
            EditorGUILayout.BeginHorizontal(GUILayout.Width(position.width), GUILayout.Height(position.height));
            {
                GUILayout.Space(2f);
                EditorGUILayout.BeginVertical(GUILayout.Width(position.width * 0.4f));
                {
                    GUILayout.Space(5f);
                    EditorGUILayout.LabelField("资源列表", EditorStyles.boldLabel);
                    EditorGUILayout.BeginHorizontal("box", GUILayout.Height(position.height - 52f));
                    {
                        DrawSourceAssetsView();
                    }
                    EditorGUILayout.EndHorizontal();

                }

                EditorGUILayout.EndVertical();
                GUILayout.Space(10f);
                EditorGUILayout.BeginVertical(GUILayout.Width(position.width * 0.5f));
                {
                    GUILayout.Space(5f);
                    EditorGUILayout.LabelField("资源依赖列表", EditorStyles.boldLabel);
                    EditorGUILayout.BeginHorizontal("box", GUILayout.Height(300));
                    {
                        //DrawDependsView();
                        m_DependsViewScroll = EditorGUILayout.BeginScrollView(m_DependsViewScroll);
                        {
                            DrawDependsView();
                        }
                        EditorGUILayout.EndScrollView();

                    }
                    EditorGUILayout.EndHorizontal();


                    EditorGUILayout.LabelField("引用该资源的列表", EditorStyles.boldLabel);
                    EditorGUILayout.BeginHorizontal("box", GUILayout.Height(300));
                    {
                        //DrawReferencesView();
                        m_ReferencesViewScroll = EditorGUILayout.BeginScrollView(m_ReferencesViewScroll);
                        {
                            DrawReferencesView();
                        }
                        EditorGUILayout.EndScrollView();

                    }
                    EditorGUILayout.EndHorizontal();


                }
                EditorGUILayout.EndVertical();
            }
            EditorGUILayout.EndHorizontal();
        }


        Vector2 m_SourceAssetsViewScroll = Vector2.zero;
        Vector2 m_DependsViewScroll = Vector2.zero;
        Vector2 m_ReferencesViewScroll = Vector2.zero;
        private AssetFolder m_assetsFolder = new AssetFolder();
        private int m_CurrentAssetRowOnDraw = 0;
        private AssetFile m_selected = null;
        private bool m_inDisplayArea = false;
        private void DrawSourceAssetsView()
        {
            m_CurrentAssetRowOnDraw = 0;
            m_SourceAssetsViewScroll = EditorGUILayout.BeginScrollView(m_SourceAssetsViewScroll);
            {
                DrawAssetFolder(m_assetsFolder);
            }
            EditorGUILayout.EndScrollView();
        }
        private void DrawAssetFolder(AssetFolder folder)
        {
            EditorGUILayout.BeginHorizontal();
            {
                //是否可以展开
                if (folder.Count > 0)
                {
                    folder.Foldout = EditorGUI.Foldout(new Rect(18f + 14f * folder.Depth, 20f * m_CurrentAssetRowOnDraw + 4f, int.MaxValue, 14f), folder.Foldout, string.Empty, true);
                }

                //图标加文件加名
                GUI.DrawTexture(new Rect(32f + 14f * folder.Depth, 20f * m_CurrentAssetRowOnDraw + 3f, 16f, 16f), AssetFolder.Icon);
                EditorGUILayout.LabelField(string.Empty, GUILayout.Width(44f + 14f * folder.Depth), GUILayout.Height(18f));
                EditorGUILayout.LabelField(folder.Name);
            }
            EditorGUILayout.EndHorizontal();
            m_CurrentAssetRowOnDraw++;




            if (folder.Foldout)
            {
                foreach (var subFolder in folder.m_folders)
                {
                    DrawAssetFolder(subFolder);
                }
                foreach (var subFile in folder.m_files)
                {
                    DrawAssetFile(subFile);
                }
            }
        }
        private void DrawAssetFile(AssetFile file)
        {
            EditorGUILayout.BeginHorizontal();
            {
                float emptySpace = position.width * 0.4f;
                if (EditorGUILayout.Toggle(file == m_selected, GUILayout.Width(emptySpace - 12f)))
                {
                    SelectFile(file);
                }
                GUILayout.Space(-emptySpace + 12f);
                //图标加文件加名
                GUI.DrawTexture(new Rect(32f + 14f * file.Depth, 20f * m_CurrentAssetRowOnDraw + 3f, 16f, 16f),file.Icon);
                EditorGUILayout.LabelField(string.Empty, GUILayout.Width(44f + 14f * file.Depth),  GUILayout.Height(18f));
                EditorGUILayout.LabelField(file.Name);
                //GUILayout.Space(100);
                GUI.Label(new Rect(450f, 20f * m_CurrentAssetRowOnDraw + 3f, 100f, 16f), $"{file.DependCount}   {file.ReferenceCount}");
            }
            EditorGUILayout.EndHorizontal();
            m_CurrentAssetRowOnDraw++;
        }


        private List<string> m_selectedDepends = new List<string>();
        private void DrawDependsView()
        {
            if (m_selected == null) return;
            m_CurrentAssetRowOnDraw = 0;

            foreach (var filePath in m_selectedDepends)
            {
                EditorGUILayout.BeginHorizontal();
                {
                    //float emptySpace = position.width;
                    //GUILayout.Space(-emptySpace + 12f);
                    //图标加文件加名
                    //GUI.DrawTexture(new Rect(32f + 14f * 0, 20f * m_CurrentAssetRowOnDraw + 3f, 16f, 16f),file.Icon);
                    EditorGUILayout.LabelField(string.Empty, GUILayout.Width(44f + 14f * 0),  GUILayout.Height(18f));
                    //EditorGUILayout.LabelField(filePath);
                    if (GUILayout.Button(filePath))
                    {
                        var assetObject = AssetDatabase.LoadAssetAtPath<Object>(filePath);
                        EditorUtility.FocusProjectWindow();
                        Selection.activeObject = assetObject;
                        EditorGUIUtility.PingObject(assetObject);
                    }
                }
                EditorGUILayout.EndHorizontal();
                m_CurrentAssetRowOnDraw++;
            }
        }
        private List<string> m_selectedReferences = new List<string>();
        private void DrawReferencesView()
        {
            if (m_selected == null) return;
            m_CurrentAssetRowOnDraw = 0;
            foreach (var filePath in m_selectedReferences)
            {
                EditorGUILayout.BeginHorizontal();
                {
                    //float emptySpace = position.width;
                    //GUILayout.Space(-emptySpace + 12f);
                    //图标加文件加名
                    //GUI.DrawTexture(new Rect(32f + 14f * 0, 20f * m_CurrentAssetRowOnDraw + 3f, 16f, 16f),file.Icon);
                    EditorGUILayout.LabelField(string.Empty, GUILayout.Width(44f + 14f * 0),  GUILayout.Height(18f));
                    //EditorGUILayout.LabelField(filePath);
                    if (GUILayout.Button(filePath))
                    {
                        var assetObject = AssetDatabase.LoadAssetAtPath<Object>(filePath);
                        EditorUtility.FocusProjectWindow();
                        Selection.activeObject = assetObject;
                        EditorGUIUtility.PingObject(assetObject);
                    }
                }
                EditorGUILayout.EndHorizontal();
                m_CurrentAssetRowOnDraw++;
            }
        }








        void SelectFile(AssetFile file)
        {
            if (m_selected == file)
                return;
            m_selected = file;

            string guid = AssetDatabase.AssetPathToGUID(m_selected.Path);

            var assetObject = AssetDatabase.LoadAssetAtPath<Object>(m_selected.Path);
            EditorUtility.FocusProjectWindow();
            Selection.activeObject = assetObject;
            EditorGUIUtility.PingObject(assetObject);

            m_selectedDepends.Clear();
            List<string> depends = null;
            if (m_dictDepend.TryGetValue(guid, out depends))
            {
                foreach (var dependGuid in depends)
                {
                    string dependPath = AssetDatabase.GUIDToAssetPath(dependGuid);
                    m_selectedDepends.Add(dependPath);
                }
            }

            m_selectedReferences.Clear();
            List<string> references = null;
            if (m_dictReference.TryGetValue(guid, out references))
            {
                foreach (var referenceGuid in references)
                {
                    string referencePath = AssetDatabase.GUIDToAssetPath(referenceGuid);
                    m_selectedReferences.Add(referencePath);
                }
            }

        }
        void CollectData()
        {
            m_listFiles.Clear();
            m_dictPath2AssetFile.Clear();
            m_selected = null;

            var assetPaths = AssetDatabase.GetAllAssetPaths();

            HashSet<string> hashSet = new HashSet<string>();
            //Dictionary<string, string> dictPath2Guid = new Dictionary<string, string>();
            //Dictionary<string, string> dictGuid2Path = new Dictionary<string, string>();
            string assetGuid = "";
            foreach (var assetPath in assetPaths)
            {
                if (!(assetPath.StartsWith("Assets/Arts") || assetPath.StartsWith("Assets/ResourcesAssets")))
                {
                    continue;
                }

                if (!File.Exists(assetPath))
                    continue;

                assetGuid = AssetDatabase.AssetPathToGUID(assetPath);

                if (hashSet.Contains(assetGuid))
                {
                    Debug.LogError($"----已存在！！！{assetGuid}  {assetPath}");
                    return;
                }
                hashSet.Add(assetGuid);
                m_listFiles.Add(assetPath);

                //if (m_listFiles.Count >= 500) break;

                //dictPath2Guid.Add(assetPath, assetGuid);
                //dictGuid2Path.Add(assetGuid, assetPath);

                //AssetItem item = new AssetItem()
                //{
                //    m_guid = assetGuid,
                //    m_path = assetPath,
                //};
            }

            m_listFiles.Sort((a, b) => a.CompareTo(b) );

            float index = 0;
            float len = m_listFiles.Count;
            foreach (var assetPath in m_listFiles)
            {
                if (index++ % 100 == 0 && EditorUtility.DisplayCancelableProgressBar($"{index}/{len}", $"{assetPath}", index / len))
                {

                }

                assetGuid = AssetDatabase.AssetPathToGUID(assetPath);

                string[] dependPaths = AssetDatabase.GetDependencies(assetPath);

                foreach (var dependPath in dependPaths)
                {
                    if (assetPath == dependPath) continue;

                    var dependGuid = AssetDatabase.AssetPathToGUID(dependPath);
                    //依赖
                    List<string> depends;
                    if (!m_dictDepend.TryGetValue(assetGuid, out depends))
                    {
                        depends = new List<string>();
                        m_dictDepend.Add(assetGuid, depends);
                    }
                    depends.Add(dependGuid);

                    //引用
                    List<string> references;
                    if (!m_dictReference.TryGetValue(dependGuid, out references))
                    {
                        references = new List<string>();
                        m_dictReference.Add(dependGuid, references);
                    }
                    references.Add(assetGuid);
                }
            }
            EditorUtility.ClearProgressBar();




            m_assetsFolder = new AssetFolder()
            {
                Name = "Assets",
            };



            int reference_zero_count = 0;
            foreach (var filePath in m_listFiles)
            {
                var fileGuid = AssetDatabase.AssetPathToGUID(filePath);

                var dependCount = 0;
                if (m_dictDepend.ContainsKey(fileGuid))
                {
                    dependCount = m_dictDepend[fileGuid].Count;
                }
                var referenceCount = 0;
                if (m_dictReference.ContainsKey(fileGuid))
                {
                    referenceCount = m_dictReference[fileGuid].Count;
                }


                //if (referenceCount == 0)
                {
                    var paths = filePath.Split('/');
                    int pathsLen = paths.Length;
                    StringBuilder sb = new StringBuilder("Assets/");
                    string pathName = "";
                    AssetFolder folder = m_assetsFolder;
                    AssetFile file = null;
                    for (int i = 1; i < pathsLen; i++)
                    {
                        pathName = paths[i];
                        if (i < pathsLen - 1)
                        {
                            sb.Append($"{pathName}/");
                            folder = folder.AddFolder(pathName, sb.ToString(), i);
                        }
                        else
                        {
                            sb.Append(pathName);
                            file = folder.AddFile(pathName, sb.ToString(), i);
                            file.DependCount = dependCount;
                            file.ReferenceCount = referenceCount;
                            m_dictPath2AssetFile.Add(file.Path, file);
                        }

                    }
                }







                /*
                if (referenceCount == 0)
                {
                    reference_zero_count++;

                    sb =
                        new StringBuilder(
                            $"{filePath}  依赖数:{dependCount}  被引用数:{referenceCount}");

                    //sb.AppendLine();
                    //foreach (var _guid in m_dictReference[fileGuid])
                    //{
                    //    sb.AppendLine($"{AssetDatabase.GUIDToAssetPath(_guid)}");
                    //}

                    Debug.Log(sb);
                }*/
            }


            Debug.Log($"总文件数:{m_listFiles.Count} 被引用为0的文件数:{reference_zero_count}");


            string[] assetGUIDs = Selection.assetGUIDs;
            foreach (var _assetGuid in assetGUIDs)
            {
                var path = AssetDatabase.GUIDToAssetPath(_assetGuid);
                var dir = Path.GetDirectoryName(path);
                var paths = path.Split('/');
                AssetFolder folder = m_assetsFolder;
                for (int i = 1; i < paths.Length; ++i)
                {
                    if (!folder.m_dictFolder.TryGetValue(paths[i], out folder))
                    {
                        break;
                    }

                    m_assetsFolder.m_foldout = true;
                    folder.m_foldout = true;
                }
            }

        }

    }


}
